package com.heima.article.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.heima.article.dto.ArticleCache;
import com.heima.article.dto.ArticleStreamMessage;
import com.heima.article.entity.ApArticle;
import com.heima.article.service.IApArticleService;
import com.heima.article.service.IComputeService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class ComputeServiceImpl implements IComputeService {
    @Autowired
    private IApArticleService apArticleService;
    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 计算文章得分
     */
    @Override
    public void compute() {
        System.out.println("定时计算文章分值任务开始执行..." + new Date());
        // 查询前5天的文章 从当天的0点0分0秒 往前推5天
        LambdaQueryWrapper<ApArticle> query = new LambdaQueryWrapper<>();
        //当天的零点零时零分
        Date end = DateUtil.beginOfDay(new Date());
        //指定时间偏移5天
        Date start = DateUtil.offsetDay(end, -5);
        query.eq(ApArticle::getIsDown, false)
                .eq(ApArticle::getIsDelete, false)
                .lt(ApArticle::getPublishTime, end)
                .gt(ApArticle::getPublishTime, start);
        List<ApArticle> list = apArticleService.list(query);
        //计算每篇文章的得分
        for (ApArticle apArticle : list) {
            Double score = computeScore(apArticle);
            // 缓存文章和分值到redis中  包含推荐首页 和 频道首页
            // 定义推荐首页的key
            String key = "hot_article_0";
            //只缓存不变的字段
            ArticleCache articleCache = new ArticleCache();
            BeanUtils.copyProperties(apArticle, articleCache);
            String value = JSON.toJSONString(articleCache);
            redisTemplate.opsForZSet().add(key, value, score);
            //定义频道首页的key

            String channelKey = "hot_article_" + apArticle.getChannelId();
            redisTemplate.opsForZSet().add(channelKey, value, score);

            //设置过期时间
            redisTemplate.expire(key, 23 * 60 + 58, TimeUnit.MINUTES);
            redisTemplate.expire(channelKey, 23 * 60 + 58, TimeUnit.MINUTES);
        }

    }

    /**
     * 更新文章分值
     *
     * @param message
     */
    @Override
    public void update(ArticleStreamMessage message) {
        // 根据文章id查询文章
        ApArticle article = apArticleService.getById(message.getArticleId());
        // 一段时间内聚合的结果
        // 计算本次聚合的分值
        Double score = computeScore(message);
        // 更新redis中的分值
        // 判断文章是否已经存在与redis中
        String key = "hot_article_"+article.getChannelId();
        ArticleCache articleCache = new ArticleCache();
        BeanUtils.copyProperties(article,articleCache);
        String value = JSON.toJSONString(articleCache);
        Double aDouble = redisTemplate.opsForZSet().score(key, value);
        if (aDouble == null){
            //redis中没有该文章,先计算历史分值,再加上增量分值,写入到redis中
            Double historyScore = computeScore(article);
            Double allScore = historyScore + score ;
            redisTemplate.opsForZSet().add(key,value,allScore);
            redisTemplate.opsForZSet().add("hot_article_0",value,allScore);
            //添加过期时间
            redisTemplate.expire(key,23 * 60 +58 ,TimeUnit.MINUTES);
            redisTemplate.expire("hot_article_0",23 * 60 +58 ,TimeUnit.MINUTES);
            System.out.println("更新文章表数据: 阅读量: " + message.getView() + ",点赞量: " + message.getLike() + ",评论量: " + message.getComment()
                    + " ,收藏量: " + message.getCollect());
        }else {
            //如果存在的话,直接将增量的分值加在原有的分值上
            //incrementScore()方法是在原有的基础增加分数
            redisTemplate.opsForZSet().incrementScore(key,value,score);
            redisTemplate.opsForZSet().incrementScore("hot_article_0",value,score);
            System.out.println("文章在redis中已经存在,增加分数是: " + score);
        }

        //更新文章表的数据
        LambdaUpdateWrapper<ApArticle> update = new LambdaUpdateWrapper<>();
        update.eq(ApArticle::getId ,message.getArticleId());
        update.setSql("views = views + " + message.getView());
        update.setSql("likes = likes + " + message.getLike());
        update.setSql("comment = comment + " + message.getComment());
        update.setSql("collection = collection + " + message.getCollect());
        apArticleService.update(update);
        System.out.println("更新文章表数据: 阅读量: " + message.getView() + ",点赞量: " + message.getLike() + ",评论量: " + message.getComment()
                + " ,收藏量: " + message.getCollect());
    }

    /**
     * 计算当日的增量分值
     *
     * @param message
     * @return
     */
    private Double computeScore(ArticleStreamMessage message) {
        double score = 0;
        score += message.getView();
        score += message.getLike() * 3;
        score += message.getComment() * 5;
        score += message.getCollect() * 8;
        return score * 3;

    }

    /**
     * 计算文章的得分
     *
     * @param article
     * @return
     */
    private Double computeScore(ApArticle article) {
        double score = 0;
        // 计算每篇文章的分值  阅读+1 点赞+3 评论+5 收藏+8
        if (article.getViews() != null) {
            score += article.getViews();
        }
        if (article.getLikes() != null) {
            score += article.getLikes() * 3;
        }
        if (article.getComment() != null) {
            score += article.getComment() * 5;
        }
        if (article.getCollection() != null) {
            score += article.getCollection() * 8;
        }
        return score;
    }


}
